﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.Party.MobilePartyAi
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using Helpers;
using System;
using System.Collections.Generic;
using TaleWorlds.CampaignSystem.Map;
using TaleWorlds.CampaignSystem.MapEvents;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem.Party
{
  public class MobilePartyAi
  {
    private const float AiCheckInterval = 0.25f;
    private const int FleeToNearbyPartyDistanceRadius = 10;
    private const int FleeToNearbySettlementDistanceRadius = 20;
    public const float GoAroundPartyWaitNearbyRadiusMultiplier = 1.2f;
    private const float HideoutPatrolRadius = 25f;
    private const float FortificationPatrolRadius = 30f;
    private const float VillagePatrolRadius = 15f;
    private const float MaximumJoiningRadiusMultiplier = 2f;
    private static readonly List<(float, Vec2)> DangerousPartiesAndTheirVecs = new List<(float, Vec2)>();
    [SaveableField(2)]
    private bool _isDisabled;
    [SaveableField(5)]
    private readonly MobileParty _mobileParty;
    [SaveableField(6)]
    public int HourCounter;
    [SaveableField(12)]
    internal Vec2 BehaviorTarget;
    [SaveableField(13)]
    private float _attackInitiative = 1f;
    [SaveableField(14)]
    private float _avoidInitiative = 1f;
    [SaveableField(15)]
    private CampaignTime _initiativeRestoreTime;
    [SaveableField(16)]
    private bool _aiBehaviorResetNeeded;
    [SaveableField(18)]
    private CampaignTime _nextAiCheckTime;
    [SaveableField(19)]
    internal bool DefaultBehaviorNeedsUpdate;
    [SaveableField(20)]
    private int _numberOfRecentFleeingFromAParty;
    [SaveableField(21)]
    private AiBehavior _defaultBehavior;
    [SaveableField(22)]
    private bool _aiPathMode;
    [SaveableField(23)]
    private bool _aiPathNeeded;
    [SaveableField(25)]
    private Vec2 _formationPosition;
    [SaveableField(28)]
    private Vec2 _moveTargetPoint;
    [SaveableField(29)]
    private Vec2 _aiPathLastPosition;
    [SaveableField(30)]
    private IMapEntity _aiBehaviorMapEntity;
    [CachedData]
    private PathFaceRecord _targetAiFaceIndex = PathFaceRecord.NullFaceRecord;
    [CachedData]
    private PathFaceRecord _moveTargetAiFaceIndex = PathFaceRecord.NullFaceRecord;
    [CachedData]
    private PathFaceRecord _aiPathLastFace;
    [CachedData]
    private List<MobileParty> _lastTargetedParties;
    private bool _aiPathNotFound;

    internal static void AutoGeneratedStaticCollectObjectsMobilePartyAi(
      object o,
      List<object> collectedObjects)
    {
      ((MobilePartyAi) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      collectedObjects.Add((object) this._mobileParty);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this._initiativeRestoreTime, collectedObjects);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this._nextAiCheckTime, collectedObjects);
      collectedObjects.Add((object) this._aiBehaviorMapEntity);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this._enableAgainAtHour, collectedObjects);
      collectedObjects.Add((object) this.MoveTargetParty);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.DoNotAttackMainPartyUntil, collectedObjects);
    }

    internal static object AutoGeneratedGetMemberValue_enableAgainAtHour(object o)
    {
      return (object) ((MobilePartyAi) o)._enableAgainAtHour;
    }

    internal static object AutoGeneratedGetMemberValueRethinkAtNextHourlyTick(object o)
    {
      return (object) ((MobilePartyAi) o).RethinkAtNextHourlyTick;
    }

    internal static object AutoGeneratedGetMemberValueDoNotMakeNewDecisions(object o)
    {
      return (object) ((MobilePartyAi) o).DoNotMakeNewDecisions;
    }

    internal static object AutoGeneratedGetMemberValueIsAlerted(object o)
    {
      return (object) ((MobilePartyAi) o).IsAlerted;
    }

    internal static object AutoGeneratedGetMemberValuePartyMoveMode(object o)
    {
      return (object) ((MobilePartyAi) o).PartyMoveMode;
    }

    internal static object AutoGeneratedGetMemberValueMoveTargetParty(object o)
    {
      return (object) ((MobilePartyAi) o).MoveTargetParty;
    }

    internal static object AutoGeneratedGetMemberValueNextTargetPosition(object o)
    {
      return (object) ((MobilePartyAi) o).NextTargetPosition;
    }

    internal static object AutoGeneratedGetMemberValueDoNotAttackMainPartyUntil(object o)
    {
      return (object) ((MobilePartyAi) o).DoNotAttackMainPartyUntil;
    }

    internal static object AutoGeneratedGetMemberValueHourCounter(object o)
    {
      return (object) ((MobilePartyAi) o).HourCounter;
    }

    internal static object AutoGeneratedGetMemberValueBehaviorTarget(object o)
    {
      return (object) ((MobilePartyAi) o).BehaviorTarget;
    }

    internal static object AutoGeneratedGetMemberValueDefaultBehaviorNeedsUpdate(object o)
    {
      return (object) ((MobilePartyAi) o).DefaultBehaviorNeedsUpdate;
    }

    internal static object AutoGeneratedGetMemberValue_isDisabled(object o)
    {
      return (object) ((MobilePartyAi) o)._isDisabled;
    }

    internal static object AutoGeneratedGetMemberValue_mobileParty(object o)
    {
      return (object) ((MobilePartyAi) o)._mobileParty;
    }

    internal static object AutoGeneratedGetMemberValue_attackInitiative(object o)
    {
      return (object) ((MobilePartyAi) o)._attackInitiative;
    }

    internal static object AutoGeneratedGetMemberValue_avoidInitiative(object o)
    {
      return (object) ((MobilePartyAi) o)._avoidInitiative;
    }

    internal static object AutoGeneratedGetMemberValue_initiativeRestoreTime(object o)
    {
      return (object) ((MobilePartyAi) o)._initiativeRestoreTime;
    }

    internal static object AutoGeneratedGetMemberValue_aiBehaviorResetNeeded(object o)
    {
      return (object) ((MobilePartyAi) o)._aiBehaviorResetNeeded;
    }

    internal static object AutoGeneratedGetMemberValue_nextAiCheckTime(object o)
    {
      return (object) ((MobilePartyAi) o)._nextAiCheckTime;
    }

    internal static object AutoGeneratedGetMemberValue_numberOfRecentFleeingFromAParty(object o)
    {
      return (object) ((MobilePartyAi) o)._numberOfRecentFleeingFromAParty;
    }

    internal static object AutoGeneratedGetMemberValue_defaultBehavior(object o)
    {
      return (object) ((MobilePartyAi) o)._defaultBehavior;
    }

    internal static object AutoGeneratedGetMemberValue_aiPathMode(object o)
    {
      return (object) ((MobilePartyAi) o)._aiPathMode;
    }

    internal static object AutoGeneratedGetMemberValue_aiPathNeeded(object o)
    {
      return (object) ((MobilePartyAi) o)._aiPathNeeded;
    }

    internal static object AutoGeneratedGetMemberValue_formationPosition(object o)
    {
      return (object) ((MobilePartyAi) o)._formationPosition;
    }

    internal static object AutoGeneratedGetMemberValue_moveTargetPoint(object o)
    {
      return (object) ((MobilePartyAi) o)._moveTargetPoint;
    }

    internal static object AutoGeneratedGetMemberValue_aiPathLastPosition(object o)
    {
      return (object) ((MobilePartyAi) o)._aiPathLastPosition;
    }

    internal static object AutoGeneratedGetMemberValue_aiBehaviorMapEntity(object o)
    {
      return (object) ((MobilePartyAi) o)._aiBehaviorMapEntity;
    }

    public bool IsDisabled
    {
      get => this._isDisabled;
      private set => this._isDisabled = value;
    }

    [SaveableProperty(3)]
    private CampaignTime _enableAgainAtHour { get; set; }

    [SaveableProperty(10)]
    public bool RethinkAtNextHourlyTick { get; set; }

    [SaveableProperty(11)]
    public bool DoNotMakeNewDecisions { get; private set; }

    [SaveableProperty(17)]
    public bool IsAlerted { get; private set; }

    [SaveableProperty(24)]
    public MoveModeType PartyMoveMode { get; private set; }

    [SaveableProperty(26)]
    public MobileParty MoveTargetParty { get; private set; }

    [SaveableProperty(27)]
    public Vec2 NextTargetPosition { get; private set; }

    [SaveableProperty(31)]
    public CampaignTime DoNotAttackMainPartyUntil { get; internal set; }

    [CachedData]
    public int PathBegin { get; private set; }

    [CachedData]
    public NavigationPath Path { get; private set; }

    [CachedData]
    public bool ForceAiNoPathMode { get; set; }

    public AiBehavior DefaultBehavior
    {
      get => this._defaultBehavior;
      private set
      {
        if (this._defaultBehavior == value)
          return;
        this._numberOfRecentFleeingFromAParty = 0;
        this._defaultBehavior = value;
        this.DefaultBehaviorNeedsUpdate = true;
        if (this._mobileParty == MobileParty.MainParty || this._mobileParty.BesiegedSettlement == null || value == AiBehavior.BesiegeSettlement || value == AiBehavior.EscortParty || value == AiBehavior.AssaultSettlement)
          return;
        this._mobileParty.ResetBesiegedSettlement();
      }
    }

    public bool NeedTargetReset => this._numberOfRecentFleeingFromAParty >= 6;

    public int NumberOfRecentFleeingFromAParty => this._numberOfRecentFleeingFromAParty;

    private float AvoidInitiative
    {
      get => !this._initiativeRestoreTime.IsPast ? this._avoidInitiative : 1f;
    }

    private float AttackInitiative
    {
      get => !this._initiativeRestoreTime.IsPast ? this._attackInitiative : 1f;
    }

    public PartyBase AiBehaviorPartyBase { get; private set; }

    public IMapEntity AiBehaviorMapEntity
    {
      get => this._aiBehaviorMapEntity;
      set
      {
        if (this._aiBehaviorMapEntity == value)
          return;
        this._aiBehaviorMapEntity = value;
        this.AiBehaviorPartyBase = (PartyBase) null;
        if (this._aiBehaviorMapEntity != null)
        {
          if (this._aiBehaviorMapEntity is MobileParty behaviorMapEntity1)
          {
            this.AiBehaviorPartyBase = behaviorMapEntity1.Party;
          }
          else
          {
            if (!(this._aiBehaviorMapEntity is Settlement behaviorMapEntity))
              return;
            this.AiBehaviorPartyBase = behaviorMapEntity.Party;
          }
        }
        else
          this.AiBehaviorPartyBase = (PartyBase) null;
      }
    }

    internal MobilePartyAi(MobileParty mobileParty)
    {
      this._mobileParty = mobileParty;
      this.RethinkAtNextHourlyTick = false;
      this.HourCounter = MBRandom.RandomInt(100);
      this._lastTargetedParties = new List<MobileParty>();
      this.InitCached();
      this._formationPosition.x = 10000f;
      this._formationPosition.y = 10000f;
      while ((double) this._formationPosition.LengthSquared > 0.36000001430511475 || (double) this._formationPosition.LengthSquared < 0.2199999988079071)
        this._formationPosition = new Vec2((float) ((double) MBRandom.RandomFloat * 1.2000000476837158 - 0.60000002384185791), (float) ((double) MBRandom.RandomFloat * 1.2000000476837158 - 0.60000002384185791));
    }

    internal void StartUp()
    {
      this.NextTargetPosition = this._mobileParty.Position2D;
      this._aiPathLastFace = PathFaceRecord.NullFaceRecord;
      this._moveTargetPoint = this._mobileParty.Position2D;
      this.ForceAiNoPathMode = false;
    }

    internal void OnGameInitialized()
    {
      this.UpdatePathModeWithPosition(this._moveTargetPoint);
      this.ComputePath(this._moveTargetPoint);
    }

    internal void InitCached()
    {
      this.Path = new NavigationPath();
      this._aiPathLastFace = PathFaceRecord.NullFaceRecord;
      this.ForceAiNoPathMode = false;
    }

    internal void PreAfterLoad()
    {
      if (this.AiBehaviorMapEntity == null)
        return;
      if (this.AiBehaviorMapEntity is Settlement behaviorMapEntity1)
      {
        this.AiBehaviorPartyBase = behaviorMapEntity1.Party;
      }
      else
      {
        if (!(this.AiBehaviorMapEntity is MobileParty behaviorMapEntity))
          return;
        this.AiBehaviorPartyBase = behaviorMapEntity.Party;
      }
    }

    internal void OnBeforeLoad() => this._lastTargetedParties = new List<MobileParty>();

    internal void HourlyTick()
    {
      if (this._numberOfRecentFleeingFromAParty > 5 && (double) MBRandom.RandomFloat < 0.20000000298023224)
        this._numberOfRecentFleeingFromAParty -= 5;
      this.RemoveOneOfLastTargettedPartiesWithProbability(0.2f);
    }

    internal void Tick(float dt)
    {
      if (this.DefaultBehaviorNeedsUpdate)
      {
        this._nextAiCheckTime = CampaignTime.Now;
        this.DefaultBehaviorNeedsUpdate = false;
      }
      if (this._nextAiCheckTime.IsFuture)
        return;
      this.TickInternal();
      this._nextAiCheckTime = CampaignTime.Now + CampaignTime.Seconds((long) (0.25 * (0.60000002384185791 + 0.10000000149011612 * (double) MBRandom.RandomFloat) * (this._mobileParty.ShortTermTargetParty != MobileParty.MainParty || this._mobileParty.ShortTermBehavior != AiBehavior.EngageParty ? 1.0 : 0.5) * 60.0 * 60.0));
    }

    private void TickInternal()
    {
      if (this._mobileParty.MapEvent != null)
        return;
      if (this._mobileParty == MobileParty.MainParty && MobileParty.MainParty.DefaultBehavior == AiBehavior.EngageParty && !MobileParty.MainParty.TargetParty.IsVisible)
        MobileParty.MainParty.Ai.SetMoveModeHold();
      if (this.IsDisabled && this.EnableAgainAtHourIsPast())
      {
        this.EnableAi();
      }
      else
      {
        if (this._mobileParty.Army != null && this._mobileParty.Army.LeaderParty.AttachedParties.Contains(this._mobileParty))
          return;
        AiBehavior bestAiBehavior;
        PartyBase behaviorParty;
        Vec2 bestTargetPoint;
        this.GetBehaviors(out bestAiBehavior, out behaviorParty, out bestTargetPoint);
        if (this.IsDisabled && behaviorParty == null)
          return;
        this.SetAiBehavior(bestAiBehavior, behaviorParty, bestTargetPoint);
      }
    }

    private void RemoveOneOfLastTargettedPartiesWithProbability(float probabilityToRemove)
    {
      int index1 = -1;
      for (int index2 = 0; index2 < this._lastTargetedParties.Count; ++index2)
      {
        if ((double) MBRandom.RandomFloat < (double) probabilityToRemove)
        {
          index1 = index2;
          break;
        }
      }
      if (index1 < 0)
        return;
      this._lastTargetedParties.RemoveAt(index1);
    }

    public void CheckPartyNeedsUpdate()
    {
      if (!this.DefaultBehaviorNeedsUpdate)
        return;
      this.Tick(0.0f);
      EncounterManager.HandleEncounterForMobileParty(this._mobileParty, 0.0f);
    }

    public void SetMoveModeHold()
    {
      this.DefaultBehavior = AiBehavior.Hold;
      this.SetShortTermBehavior(AiBehavior.Hold, (IMapEntity) null);
      this._mobileParty.TargetSettlement = (Settlement) null;
      this._mobileParty.TargetParty = (MobileParty) null;
    }

    public void SetMoveEngageParty(MobileParty party)
    {
      this.DefaultBehavior = AiBehavior.EngageParty;
      this._mobileParty.TargetParty = party;
      this._mobileParty.TargetSettlement = (Settlement) null;
    }

    public void SetMoveGoAroundParty(MobileParty party)
    {
      this.DefaultBehavior = AiBehavior.GoAroundParty;
      this._mobileParty.TargetParty = party;
      this._mobileParty.TargetSettlement = (Settlement) null;
    }

    public void SetMoveGoToSettlement(Settlement settlement)
    {
      this.DefaultBehavior = AiBehavior.GoToSettlement;
      this._mobileParty.TargetSettlement = settlement;
      this._mobileParty.TargetParty = (MobileParty) null;
      this._mobileParty.TargetPosition = settlement.GatePosition;
    }

    public void SetMoveGoToPoint(Vec2 point)
    {
      this.DefaultBehavior = AiBehavior.GoToPoint;
      this._mobileParty.TargetPosition = point;
      this._mobileParty.TargetSettlement = (Settlement) null;
      this._mobileParty.TargetParty = (MobileParty) null;
    }

    public void SetMoveEscortParty(MobileParty mobileParty)
    {
      this.DefaultBehavior = AiBehavior.EscortParty;
      this._mobileParty.TargetParty = mobileParty;
      this._mobileParty.TargetSettlement = (Settlement) null;
    }

    public void SetMovePatrolAroundPoint(Vec2 point)
    {
      this._mobileParty.TargetParty = (MobileParty) null;
      this._mobileParty.TargetSettlement = (Settlement) null;
      this.DefaultBehavior = AiBehavior.PatrolAroundPoint;
      this._mobileParty.TargetPosition = point;
      this._aiBehaviorResetNeeded = true;
    }

    public void SetMovePatrolAroundSettlement(Settlement settlement)
    {
      this.SetMovePatrolAroundPoint(settlement.GatePosition);
      this._mobileParty.TargetSettlement = settlement;
      this._mobileParty.TargetParty = (MobileParty) null;
    }

    public void SetMoveRaidSettlement(Settlement settlement)
    {
      this.DefaultBehavior = AiBehavior.RaidSettlement;
      this._mobileParty.TargetSettlement = settlement;
      this._mobileParty.TargetParty = (MobileParty) null;
    }

    public void SetMoveBesiegeSettlement(Settlement settlement)
    {
      if (this._mobileParty.BesiegedSettlement != null && this._mobileParty.BesiegedSettlement != settlement)
        this._mobileParty.ResetBesiegedSettlement();
      this.DefaultBehavior = AiBehavior.BesiegeSettlement;
      this._mobileParty.TargetSettlement = settlement;
      this._mobileParty.TargetParty = (MobileParty) null;
    }

    public void SetMoveDefendSettlement(Settlement settlement)
    {
      this.DefaultBehavior = AiBehavior.DefendSettlement;
      this._mobileParty.TargetSettlement = settlement;
      this._mobileParty.TargetParty = (MobileParty) null;
    }

    internal void GetBehaviors(
      out AiBehavior bestAiBehavior,
      out PartyBase behaviorParty,
      out Vec2 bestTargetPoint)
    {
      bestAiBehavior = this._mobileParty.DefaultBehavior;
      MobileParty mobileParty = this._mobileParty.TargetParty;
      bestTargetPoint = this._mobileParty.TargetPosition;
      Vec2 averageEnemyVec = new Vec2(0.0f, 0.0f);
      MobileParty bestInitiativeAllyPartyToEscort = (MobileParty) null;
      if (Campaign.Current.GameStarted && this._mobileParty != MobileParty.MainParty && this._mobileParty.BesiegedSettlement == null && (this._mobileParty.Army == null || !this._mobileParty.Army.LeaderParty.AttachedParties.Contains(this._mobileParty)))
      {
        AiBehavior bestInitiativeBehavior;
        MobileParty bestInitiativeTargetParty;
        float bestInitiativeBehaviorScore;
        this.GetBestInitiativeBehavior(out bestInitiativeBehavior, out bestInitiativeTargetParty, out bestInitiativeBehaviorScore, out averageEnemyVec);
        if (!this.DoNotMakeNewDecisions || bestInitiativeTargetParty != null && this._mobileParty.TargetSettlement != null && (bestInitiativeTargetParty.MapEvent != null && bestInitiativeTargetParty.MapEvent.MapEventSettlement == this._mobileParty.TargetSettlement || bestInitiativeTargetParty.BesiegedSettlement == this._mobileParty.TargetSettlement))
        {
          if (this._mobileParty.ShortTermBehavior == AiBehavior.EngageParty && this._mobileParty.ShortTermTargetParty != null && ((double) bestInitiativeBehaviorScore < 1.0 || bestInitiativeBehavior != AiBehavior.EngageParty || bestInitiativeTargetParty != this._mobileParty.ShortTermTargetParty))
            this._lastTargetedParties.Add(this._mobileParty.ShortTermTargetParty);
          if ((double) bestInitiativeBehaviorScore > 1.0)
          {
            bestAiBehavior = bestInitiativeBehavior;
            mobileParty = bestInitiativeTargetParty;
          }
          else if (this._mobileParty.ShortTermBehavior == AiBehavior.FleeToPoint || this._mobileParty.ShortTermBehavior == AiBehavior.FleeToGate)
          {
            double num1 = (double) this._mobileParty.AiBehaviorTarget.DistanceSquared(this._mobileParty.Position2D);
            float lastCalculatedSpeed = this._mobileParty._lastCalculatedSpeed;
            double num2 = (double) lastCalculatedSpeed * (double) lastCalculatedSpeed * 0.25 * 0.25;
            if (num1 >= num2)
            {
              bestAiBehavior = AiBehavior.FleeToPoint;
              mobileParty = this._mobileParty.ShortTermTargetParty;
            }
          }
          if (bestInitiativeBehavior == AiBehavior.DefendSettlement && bestInitiativeTargetParty.DefaultBehavior == AiBehavior.DefendSettlement)
          {
            if (bestInitiativeTargetParty.MapEvent != null)
            {
              bestAiBehavior = AiBehavior.EngageParty;
              mobileParty = bestInitiativeTargetParty.ShortTermTargetParty;
            }
            else
              bestInitiativeAllyPartyToEscort = bestInitiativeTargetParty;
          }
        }
      }
      this.IsAlerted = false;
      AiBehavior shortTermBehavior = bestAiBehavior;
      Vec2 vec2 = bestTargetPoint;
      Settlement shortTermTargetSettlement = this._mobileParty.TargetSettlement;
      MobileParty shortTermTargetParty = mobileParty;
      switch (bestAiBehavior)
      {
        case AiBehavior.GoToSettlement:
          if (this._mobileParty.CurrentSettlement == this._mobileParty.TargetSettlement)
          {
            this.GetInSettlementBehavior(ref shortTermBehavior, ref shortTermTargetParty);
            break;
          }
          break;
        case AiBehavior.BesiegeSettlement:
          if (!this._mobileParty.IsMainParty)
          {
            this.GetBesiegeBehavior(out shortTermBehavior, out vec2, out shortTermTargetSettlement);
            break;
          }
          break;
        case AiBehavior.EngageParty:
          this.SetShortTermBehavior(AiBehavior.EngageParty, (IMapEntity) shortTermTargetParty);
          break;
        case AiBehavior.GoAroundParty:
          this.GetGoAroundPartyBehavior(this._mobileParty.TargetParty, bestInitiativeAllyPartyToEscort, out shortTermBehavior, out vec2, out shortTermTargetParty);
          break;
        case AiBehavior.FleeToPoint:
          if (this._mobileParty.DefaultBehavior == AiBehavior.PatrolAroundPoint)
            this._aiBehaviorResetNeeded = true;
          this.IsAlerted = true;
          this.GetFleeBehavior(out shortTermBehavior, out vec2, ref shortTermTargetSettlement, mobileParty, averageEnemyVec);
          break;
        case AiBehavior.PatrolAroundPoint:
          this.GetPatrolBehavior(out shortTermBehavior, out vec2, out shortTermTargetParty, this._mobileParty.TargetPosition);
          break;
        case AiBehavior.EscortParty:
          this.GetFollowBehavior(ref shortTermBehavior, ref shortTermTargetSettlement, mobileParty);
          break;
        case AiBehavior.DefendSettlement:
          Settlement settlement = this._mobileParty.TargetSettlement ?? mobileParty.TargetSettlement;
          if (settlement.LastAttackerParty != null && settlement.LastAttackerParty.IsActive)
          {
            this.GetGoAroundPartyBehavior(settlement.LastAttackerParty, bestInitiativeAllyPartyToEscort, out shortTermBehavior, out vec2, out shortTermTargetParty);
            break;
          }
          break;
      }
      bestAiBehavior = shortTermBehavior;
      bestTargetPoint = vec2;
      if (shortTermTargetParty != null)
        mobileParty = shortTermTargetParty;
      if (bestAiBehavior == AiBehavior.GoToSettlement || bestAiBehavior == AiBehavior.RaidSettlement || bestAiBehavior == AiBehavior.AssaultSettlement || bestAiBehavior == AiBehavior.BesiegeSettlement || bestAiBehavior == AiBehavior.DefendSettlement && mobileParty == null)
        behaviorParty = shortTermTargetSettlement != null ? shortTermTargetSettlement.Party : this._mobileParty.TargetSettlement.Party;
      else
        behaviorParty = mobileParty?.Party;
    }

    private void GetInSettlementBehavior(
      ref AiBehavior shortTermBehavior,
      ref MobileParty shortTermTargetParty)
    {
      if (this._mobileParty.MapEvent == null)
        return;
      MobileParty mobileParty = this._mobileParty.MapEvent.AttackerSide.LeaderParty.MobileParty;
      if (!FactionManager.IsAtWarAgainstFaction(mobileParty.MapFaction, this._mobileParty.MapFaction))
        return;
      shortTermBehavior = AiBehavior.EngageParty;
      shortTermTargetParty = mobileParty;
    }

    private void GetFollowBehavior(
      ref AiBehavior shortTermBehavior,
      ref Settlement shortTermTargetSettlement,
      MobileParty followedParty)
    {
      shortTermBehavior = AiBehavior.EscortParty;
      if (followedParty == null || !followedParty.IsActive)
      {
        shortTermBehavior = AiBehavior.Hold;
      }
      else
      {
        if (followedParty.CurrentSettlement == null)
          return;
        shortTermBehavior = AiBehavior.GoToSettlement;
        shortTermTargetSettlement = followedParty.CurrentSettlement;
      }
    }

    private void GetBesiegeBehavior(
      out AiBehavior shortTermBehavior,
      out Vec2 shortTermTargetPoint,
      out Settlement shortTermTargetSettlement)
    {
      if (this._mobileParty.TargetSettlement != null)
      {
        if (this._mobileParty.TargetSettlement.SiegeEvent != null && this._mobileParty.TargetSettlement.SiegeEvent.BesiegerCamp.LeaderParty == this._mobileParty && this._mobileParty.TargetSettlement.SiegeEvent.BesiegerCamp.IsReadyToBesiege)
        {
          shortTermTargetSettlement = this._mobileParty.TargetSettlement;
          shortTermBehavior = AiBehavior.AssaultSettlement;
        }
        else if (this._mobileParty.BesiegedSettlement == this._mobileParty.TargetSettlement)
        {
          shortTermTargetSettlement = (Settlement) null;
          shortTermBehavior = AiBehavior.Hold;
        }
        else
        {
          shortTermTargetSettlement = this._mobileParty.TargetSettlement;
          shortTermBehavior = AiBehavior.GoToSettlement;
        }
      }
      else
      {
        shortTermTargetSettlement = (Settlement) null;
        shortTermBehavior = AiBehavior.GoToPoint;
      }
      shortTermTargetPoint = this._mobileParty.TargetSettlement.GatePosition;
    }

    private void GetFleeBehavior(
      out AiBehavior fleeBehaviorInternal,
      out Vec2 fleeTargetPoint,
      ref Settlement fleeTargetSettlement,
      MobileParty partyToFleeFrom,
      Vec2 avarageEnemyVec)
    {
      fleeBehaviorInternal = this._mobileParty.ShortTermBehavior;
      fleeTargetPoint = this._mobileParty.AiBehaviorTarget;
      if (this._mobileParty.CurrentSettlement != null)
      {
        fleeBehaviorInternal = AiBehavior.GoToSettlement;
        fleeTargetSettlement = this._mobileParty.CurrentSettlement;
      }
      else if (this._mobileParty.DefaultBehavior == AiBehavior.GoToSettlement && (partyToFleeFrom.MapEvent != null && partyToFleeFrom.MapEvent.MapEventSettlement == this._mobileParty.TargetSettlement || partyToFleeFrom.BesiegedSettlement == this._mobileParty.TargetSettlement))
      {
        fleeBehaviorInternal = AiBehavior.FleeToPoint;
        fleeTargetPoint = this._mobileParty.Position2D;
      }
      else if (this._mobileParty.ShortTermBehavior != AiBehavior.FleeToPoint || this._mobileParty.ShortTermTargetParty != partyToFleeFrom || (double) this._mobileParty.AiBehaviorTarget.Distance(this._mobileParty.Position2D) < (double) this._mobileParty._lastCalculatedSpeed * 0.25)
      {
        fleeBehaviorInternal = AiBehavior.FleeToPoint;
        fleeTargetPoint = this._mobileParty.Position2D;
        Vec2 vec2 = partyToFleeFrom.Position2D - this._mobileParty.Position2D;
        float num1 = MathF.Min(3f, vec2.Length);
        float num2 = (float) (2.0 * (double) MBRandom.RandomFloat - 1.0);
        float num3 = (float) (2.0 * (double) MBRandom.RandomFloat - 1.0);
        double num4 = (double) vec2.Normalize();
        this._mobileParty.AverageFleeTargetDirection = new Vec2((this._mobileParty.AverageFleeTargetDirection.x * (float) (this._numberOfRecentFleeingFromAParty - 1) + vec2.x) / (float) this._numberOfRecentFleeingFromAParty, (this._mobileParty.AverageFleeTargetDirection.y * (float) (this._numberOfRecentFleeingFromAParty - 1) + vec2.y) / (float) this._numberOfRecentFleeingFromAParty);
        double num5 = (double) this._mobileParty.AverageFleeTargetDirection.Normalize();
        vec2 += 3f * avarageEnemyVec;
        double num6 = (double) vec2.Normalize();
        Vec2 direction = -vec2 + 0.1f * this._mobileParty.Bearing + new Vec2(num2 * (num1 / 10f), num3 * (num1 / 10f));
        double num7 = (double) direction.Normalize();
        float distance = MathF.Min((float) (((double) partyToFleeFrom.GetTotalStrengthWithFollowers(false) + 0.10000000149011612) / ((double) this._mobileParty.GetTotalStrengthWithFollowers(false) + 0.10000000149011612) * 3.0) + (float) this.NumberOfRecentFleeingFromAParty * 2f, this._mobileParty.IsLordParty ? 10f : 5f);
        fleeBehaviorInternal = AiBehavior.FleeToPoint;
        double num8 = (double) direction.Normalize();
        this.GetAccessibleTargetPointInDirection(out fleeTargetPoint, direction, distance, this._mobileParty.Position2D, 100);
      }
      Vec2 fleeDirection = fleeTargetPoint - this._mobileParty.Position2D;
      double num = (double) fleeDirection.Normalize();
      if (this._mobileParty.IsLordParty && this._mobileParty.MapFaction.IsKingdomFaction)
      {
        (AiBehavior aiBehavior, Settlement settlement) = this.GetBehaviorForNearbySettlementToFlee(partyToFleeFrom.Position2D, fleeDirection);
        if (aiBehavior != AiBehavior.None)
        {
          fleeBehaviorInternal = aiBehavior;
          if (aiBehavior == AiBehavior.GoToSettlement)
            fleeTargetSettlement = settlement;
          else if (aiBehavior == AiBehavior.FleeToGate)
            fleeTargetPoint = settlement.GatePosition;
        }
      }
      MobileParty nearbyPartyToFlee = this.GetNearbyPartyToFlee(partyToFleeFrom, fleeDirection);
      if (nearbyPartyToFlee != null)
      {
        fleeBehaviorInternal = AiBehavior.FleeToParty;
        fleeTargetPoint = nearbyPartyToFlee.Position2D;
      }
      if (!this.IsFleeBehavior(fleeBehaviorInternal))
        return;
      ++this._numberOfRecentFleeingFromAParty;
    }

    private void GetGoAroundPartyBehavior(
      MobileParty targetParty,
      MobileParty bestInitiativeAllyPartyToEscort,
      out AiBehavior goAroundPartyBehavior,
      out Vec2 goAroundPartyTargetPoint,
      out MobileParty goAroundPartyTargetParty)
    {
      Vec2 position2D = targetParty.Position2D;
      goAroundPartyTargetPoint = position2D;
      goAroundPartyTargetParty = targetParty;
      Vec2 vec2_1 = this._mobileParty.Position2D - position2D;
      float length = vec2_1.Length;
      double num1 = (double) vec2_1.Normalize();
      bool flag = false;
      Vec2 v = goAroundPartyTargetPoint;
      for (int index1 = 5; index1 >= 0 && !flag; --index1)
      {
        int num2 = this._mobileParty.RandomInt(-4, 5);
        for (int index2 = 1; index2 <= 2 && !flag; ++index2)
        {
          for (int index3 = num2; index3 < num2 + 9; ++index3)
          {
            Vec2 vec2_2 = vec2_1;
            vec2_2.RotateCCW((float) ((double) index3 / 9.0 * 1.5707963705062866 * (double) index2 * 0.5 * ((double) MathF.Min(MathF.Max(0.0f, length - 3.60000014f), 9f) / 9.0)));
            Vec2 position = position2D + vec2_2 * 3f * 1.2f * ((float) index1 / 5f);
            if (Campaign.Current.MapSceneWrapper.AreFacesOnSameIsland(Campaign.Current.MapSceneWrapper.GetFaceIndex(this._mobileParty.Position2D), Campaign.Current.MapSceneWrapper.GetFaceIndex(position), false) && PartyBase.IsPositionOkForTraveling(position))
            {
              flag = true;
              v = position;
              break;
            }
          }
        }
      }
      if (flag)
      {
        double randomFloat = (double) MBRandom.RandomFloat;
        double num3 = 0.20000000298023224 * (double) this._mobileParty.AiBehaviorTarget.DistanceSquared(v);
        goAroundPartyTargetPoint = randomFloat < num3 || (double) targetParty._lastCalculatedSpeed > (double) this._mobileParty._lastCalculatedSpeed ? v : this._mobileParty.AiBehaviorTarget;
        goAroundPartyBehavior = AiBehavior.GoToPoint;
      }
      else
      {
        goAroundPartyBehavior = AiBehavior.EngageParty;
        goAroundPartyTargetParty = targetParty;
      }
      if (bestInitiativeAllyPartyToEscort == null || targetParty.SiegeEvent == null || targetParty.BesiegerCamp.LeaderParty != targetParty)
        return;
      goAroundPartyBehavior = AiBehavior.EscortParty;
      goAroundPartyTargetParty = bestInitiativeAllyPartyToEscort;
    }

    private void GetPatrolBehavior(
      out AiBehavior patrolBehavior,
      out Vec2 patrolTargetPoint,
      out MobileParty patrolTargetParty,
      Vec2 patrollingCenterPoint)
    {
      double num1 = (double) this._mobileParty.AiBehaviorTarget.DistanceSquared(this._mobileParty.Position2D);
      patrolBehavior = AiBehavior.GoToPoint;
      patrolTargetPoint = this._mobileParty.AiBehaviorTarget;
      patrolTargetParty = (MobileParty) null;
      if (this._mobileParty.ShortTermBehavior == AiBehavior.GoToSettlement || this._mobileParty.ShortTermBehavior == AiBehavior.EngageParty || this._mobileParty.ShortTermBehavior == AiBehavior.FleeToPoint)
        this._aiBehaviorResetNeeded = true;
      if (num1 >= 1.0 && !this._aiBehaviorResetNeeded)
        return;
      if ((double) MBRandom.RandomFloat < 0.125 || this._aiBehaviorResetNeeded)
      {
        Vec2 vec2 = patrollingCenterPoint - this._mobileParty.Position2D;
        float num2 = vec2.Normalize();
        float radiusForSettlement = this.GetMaxPatrolRadiusForSettlement();
        float num3 = MathF.Max(num2 * 0.25f, radiusForSettlement);
        if ((double) num2 > (double) num3 * (3.2000000476837158 / (this._mobileParty.IsCurrentlyUsedByAQuest ? 1.5 : 1.0)))
        {
          patrolBehavior = AiBehavior.GoToPoint;
          patrolTargetPoint = this._mobileParty.TargetSettlement != null ? this._mobileParty.TargetSettlement.GatePosition : patrollingCenterPoint;
        }
        else
        {
          float num4 = this._mobileParty.TargetSettlement == null || (double) this._mobileParty.TargetSettlement.NumberOfEnemiesSpottedAround <= 1.0 ? 0.0f : MathF.Sqrt(this._mobileParty.TargetSettlement.NumberOfEnemiesSpottedAround) - 1f;
          float num5 = MathF.Max(0.0f, MathF.Min(0.9f, (float) ((double) num2 / ((double) num3 / ((this._mobileParty.TargetSettlement == null || this._mobileParty.TargetSettlement.MapFaction != this._mobileParty.MapFaction ? 0.0 : (double) num4) + 1.0)) - 0.40000000596046448)));
          Vec2 direction = (1f - num5) * this._mobileParty.Bearing + num5 * vec2;
          direction.RotateCCW((float) (((double) MBRandom.RandomFloat - 0.30000001192092896) * 0.15000000596046448));
          double num6 = (double) direction.Normalize();
          float num7 = (float) (0.5 + 0.5 * (double) MBRandom.RandomFloat);
          float rotationChangeLimitAddition = (double) num2 > (double) radiusForSettlement * 4.0 ? 0.2f : ((double) num2 > (double) radiusForSettlement * 2.0 ? 0.4f : ((double) num2 > (double) radiusForSettlement ? 0.6f : 1f));
          this.GetAccessibleTargetPointInDirection(out patrolTargetPoint, direction, num3 * num7, patrollingCenterPoint, 20, rotationChangeLimitAddition);
        }
        this._aiBehaviorResetNeeded = false;
      }
      else
        patrolTargetPoint = this._mobileParty.Position2D;
    }

    private void GetBestInitiativeBehavior(
      out AiBehavior bestInitiativeBehavior,
      out MobileParty bestInitiativeTargetParty,
      out float bestInitiativeBehaviorScore,
      out Vec2 averageEnemyVec)
    {
      MobilePartyAi.DangerousPartiesAndTheirVecs.Clear();
      bestInitiativeBehaviorScore = 0.0f;
      bestInitiativeTargetParty = (MobileParty) null;
      bestInitiativeBehavior = AiBehavior.None;
      averageEnemyVec = Vec2.Zero;
      if (this._mobileParty.CurrentSettlement != null && (this._mobileParty.IsGarrison || this._mobileParty.IsMilitia || this._mobileParty.IsBandit))
        return;
      LocatableSearchData<MobileParty> data1 = MobileParty.StartFindingLocatablesAroundPosition(this._mobileParty.Position2D, 9f);
      MobileParty nextLocatable1 = MobileParty.FindNextLocatable(ref data1);
      while (nextLocatable1 != null)
      {
        if (nextLocatable1.MapEvent != null && MobileParty.MainParty.MapEvent == nextLocatable1.MapEvent && (MobileParty.MainParty.Army == null || MobileParty.MainParty.Army.LeaderParty == MobileParty.MainParty) && nextLocatable1 != MobileParty.MainParty)
          nextLocatable1 = MobileParty.FindNextLocatable(ref data1);
        else if (nextLocatable1 == this._mobileParty || !nextLocatable1.IsActive || !this.IsEnemy(nextLocatable1.Party) || nextLocatable1.ShouldBeIgnored || nextLocatable1.CurrentSettlement != null && !nextLocatable1.IsGarrison && !nextLocatable1.IsLordParty || this._mobileParty.CurrentSettlement?.SiegeEvent != null || nextLocatable1.IsGarrison && !this._mobileParty.IsBandit || nextLocatable1.BesiegerCamp != null && nextLocatable1.BesiegerCamp.LeaderParty != nextLocatable1 || nextLocatable1.Army != null && nextLocatable1.Army.LeaderParty != nextLocatable1 && nextLocatable1.AttachedTo != null || nextLocatable1.MapEvent != null && nextLocatable1 != MobileParty.MainParty && nextLocatable1.Party.MapEvent.MapEventSettlement == null && nextLocatable1.Party != nextLocatable1.Party.MapEvent.GetLeaderParty(BattleSideEnum.Attacker) && nextLocatable1.Party != nextLocatable1.Party.MapEvent.GetLeaderParty(BattleSideEnum.Defender) || nextLocatable1.MapEvent != null && this.IsEnemy(nextLocatable1.MapEvent.AttackerSide.LeaderParty) == this.IsEnemy(nextLocatable1.MapEvent.DefenderSide.LeaderParty) || nextLocatable1.CurrentSettlement != null && nextLocatable1.CurrentSettlement.IsHideout && this._mobileParty.IsBandit)
        {
          nextLocatable1 = MobileParty.FindNextLocatable(ref data1);
        }
        else
        {
          Vec2 v1 = nextLocatable1.BesiegedSettlement != null ? nextLocatable1.VisualPosition2DWithoutError : nextLocatable1.Position2D;
          Vec2 vec2_1 = this._mobileParty.Position2D;
          float num1 = vec2_1.Distance(v1);
          if ((double) num1 >= 6.0)
          {
            nextLocatable1 = MobileParty.FindNextLocatable(ref data1);
          }
          else
          {
            float num2 = 1f + MathF.Max(0.0f, (float) (((double) num1 - 1.0) / 4.0));
            float num3 = (double) num2 > 2.0 ? 2f : num2;
            float num4 = (float) (0.0099999997764825821 + (this._mobileParty.Army == null || this._mobileParty != this._mobileParty.Army.LeaderParty ? (double) this._mobileParty.Party.TotalStrength : (double) this._mobileParty.Army.TotalStrength));
            float aggressiveness = this._mobileParty.Aggressiveness;
            float num5 = 0.0f;
            float num6 = 0.01f;
            if (nextLocatable1.BesiegerCamp != null)
            {
              foreach (PartyBase partyBase in nextLocatable1.SiegeEvent.BesiegerCamp.GetInvolvedPartiesForEventType(MapEvent.BattleTypes.Siege))
                num6 += partyBase.TotalStrength;
            }
            else if (nextLocatable1.CurrentSettlement == null || !nextLocatable1.CurrentSettlement.IsUnderSiege)
            {
              double num7 = (double) num6;
              Army army = nextLocatable1.Army;
              double num8 = army != null ? (double) army.TotalStrength : (double) nextLocatable1.Party.TotalStrength;
              num6 = (float) (num7 + num8);
            }
            MobileParty mobileParty = (MobileParty) null;
            LocatableSearchData<MobileParty> data2 = MobileParty.StartFindingLocatablesAroundPosition(this._mobileParty.Position2D, 9f);
            MobileParty nextLocatable2 = MobileParty.FindNextLocatable(ref data2);
            while (nextLocatable2 != null)
            {
              if (this._mobileParty.MapFaction == nextLocatable2.MapFaction && nextLocatable2.BesiegedSettlement != null || nextLocatable2.MapEvent != null && nextLocatable2.MapEvent != nextLocatable1.MapEvent)
                nextLocatable2 = MobileParty.FindNextLocatable(ref data2);
              else if (nextLocatable2.AttachedTo != null)
              {
                nextLocatable2 = MobileParty.FindNextLocatable(ref data2);
              }
              else
              {
                if (nextLocatable2 != this._mobileParty && nextLocatable2 != nextLocatable1)
                {
                  Vec2 v2 = nextLocatable2.BesiegedSettlement != null ? nextLocatable2.VisualPosition2DWithoutError : nextLocatable2.Position2D;
                  double num9;
                  if (nextLocatable2 == nextLocatable1)
                  {
                    vec2_1 = this._mobileParty.Position2D;
                    num9 = (double) vec2_1.Distance(v2);
                  }
                  else
                    num9 = (double) v2.Distance(v1);
                  float num10 = (float) num9;
                  if ((double) num10 > 6.0)
                  {
                    nextLocatable2 = MobileParty.FindNextLocatable(ref data2);
                    continue;
                  }
                  if (nextLocatable2.BesiegerCamp != null && nextLocatable2.BesiegerCamp.LeaderParty != nextLocatable2)
                  {
                    nextLocatable2 = MobileParty.FindNextLocatable(ref data2);
                    continue;
                  }
                  PartyBase behaviorPartyBase = nextLocatable2.Ai.AiBehaviorPartyBase;
                  if (nextLocatable2.Army != null)
                    behaviorPartyBase = nextLocatable2.Army.LeaderParty.Ai.AiBehaviorPartyBase;
                  bool flag1 = behaviorPartyBase != null && (behaviorPartyBase == nextLocatable1.Party || behaviorPartyBase.MapEvent != null && behaviorPartyBase.MapEvent == nextLocatable1.Party.MapEvent);
                  bool flag2 = this._mobileParty.Army != null && this._mobileParty.Army == nextLocatable2.Army && this._mobileParty.Army.DoesLeaderPartyAndAttachedPartiesContain(this._mobileParty) || nextLocatable1.Army != null && nextLocatable1.Army == nextLocatable2.Army || nextLocatable1.BesiegedSettlement != null && nextLocatable1.BesiegedSettlement == nextLocatable2.BesiegedSettlement || (double) num1 > 3.0 & flag1 || (double) num10 > 3.0 & flag1 && nextLocatable1 != MobileParty.MainParty && (MobileParty.MainParty.Army == null || nextLocatable1 != MobileParty.MainParty.Army.LeaderParty);
                  if (this._mobileParty.MapFaction == nextLocatable2.MapFaction && nextLocatable1.BesiegedSettlement != null && nextLocatable2.CurrentSettlement == null && nextLocatable2.DefaultBehavior == AiBehavior.DefendSettlement && nextLocatable1.BesiegedSettlement == nextLocatable2.TargetSettlement && (double) nextLocatable2.Party.TotalStrength > (double) this._mobileParty.Party.TotalStrength * 1.25)
                    mobileParty = nextLocatable2.Army != null ? nextLocatable2.Army.LeaderParty : nextLocatable2;
                  if (flag2 || (double) num10 < 3.0 * (double) num3)
                  {
                    float num11 = MathF.Min(1f, flag2 ? 1f : ((double) num10 < 3.0 ? 1f : (float) (1.0 - ((double) num10 - 3.0) / (3.0 * ((double) num3 - 1.0)))));
                    bool flag3 = nextLocatable1.MapEvent != null && nextLocatable1.MapEvent == nextLocatable2.MapEvent;
                    float num12 = nextLocatable2.Army == null || nextLocatable2.Army.LeaderParty != nextLocatable2 ? nextLocatable2.Party.TotalStrength : nextLocatable2.Army.TotalStrength;
                    if ((((double) nextLocatable2.Aggressiveness > 0.0099999997764825821 ? 1 : (nextLocatable2.IsGarrison ? 1 : 0)) | (flag3 ? 1 : 0)) != 0 && nextLocatable2.MapFaction == nextLocatable1.MapFaction)
                    {
                      if (nextLocatable2.BesiegerCamp != null)
                      {
                        foreach (PartyBase partyBase in nextLocatable2.SiegeEvent.BesiegerCamp.GetInvolvedPartiesForEventType(MapEvent.BattleTypes.Siege))
                        {
                          if (partyBase.MobileParty.AttachedTo == null)
                          {
                            double num13 = (double) num6;
                            Army army = partyBase.MobileParty.Army;
                            double num14 = army != null ? (double) army.TotalStrength : (double) partyBase.TotalStrength;
                            num6 = (float) (num13 + num14);
                          }
                        }
                      }
                      else
                        num6 += num12 * num11;
                    }
                    if (this._mobileParty.MapFaction == nextLocatable2.MapFaction)
                    {
                      bool flag4 = (double) nextLocatable2.Aggressiveness > 0.0099999997764825821 || nextLocatable2.CurrentSettlement != null && nextLocatable2.CurrentSettlement == nextLocatable1.CurrentSettlement;
                      bool flag5 = nextLocatable1 != MobileParty.MainParty || nextLocatable2.Ai.CanAttack(MobileParty.MainParty);
                      bool flag6 = nextLocatable2.CurrentSettlement == null || !nextLocatable2.CurrentSettlement.IsHideout;
                      if ((flag3 || flag4 & flag5 & flag6) && (nextLocatable2.CurrentSettlement?.SiegeEvent == null || nextLocatable1 != nextLocatable2.CurrentSettlement.SiegeEvent.BesiegerCamp.LeaderParty))
                      {
                        if (nextLocatable2.BesiegerCamp != null)
                        {
                          foreach (PartyBase partyBase in nextLocatable2.SiegeEvent.BesiegerCamp.GetInvolvedPartiesForEventType(MapEvent.BattleTypes.Siege))
                          {
                            if (partyBase.MobileParty.AttachedTo == null)
                            {
                              double num15 = (double) num4;
                              Army army = partyBase.MobileParty.Army;
                              double num16 = army != null ? (double) army.TotalStrength : (double) partyBase.TotalStrength;
                              num4 = (float) (num15 + num16);
                              if ((double) partyBase.MobileParty.Aggressiveness > (double) aggressiveness)
                                aggressiveness = partyBase.MobileParty.Aggressiveness;
                            }
                          }
                        }
                        else
                        {
                          num4 += num12 * num11;
                          if ((double) nextLocatable2.Aggressiveness > (double) aggressiveness)
                            aggressiveness = nextLocatable2.Aggressiveness;
                          if (nextLocatable2.CurrentSettlement != null)
                            num5 += num12 * num11;
                        }
                      }
                    }
                  }
                }
                nextLocatable2 = MobileParty.FindNextLocatable(ref data2);
              }
            }
            if (this._mobileParty.CurrentSettlement != null)
              num4 -= num5;
            if (nextLocatable1.LastVisitedSettlement != null && nextLocatable1.LastVisitedSettlement.IsVillage)
            {
              vec2_1 = nextLocatable1.Position2D;
              if ((double) vec2_1.DistanceSquared(nextLocatable1.LastVisitedSettlement.Position2D) < 1.0 && nextLocatable1.LastVisitedSettlement.MapFaction.IsAtWarWith(this._mobileParty.MapFaction))
                num6 += 20f;
            }
            float localAdvantage = num4 / num6 * (!this._mobileParty.IsCaravan && !this._mobileParty.IsVillager || nextLocatable1 != MobileParty.MainParty ? 1f : 0.6f);
            if (nextLocatable1.IsCaravan)
            {
              if (this._mobileParty.IsBandit)
              {
                float playerProgress = Campaign.Current.Models.PlayerProgressionModel.GetPlayerProgress();
                localAdvantage *= (float) (2.4000000953674316 - 0.89999997615814209 * (double) playerProgress);
              }
              else if (this._mobileParty.LeaderHero != null && this._mobileParty.LeaderHero.IsMinorFactionHero)
                localAdvantage *= 1.5f;
            }
            if (nextLocatable1.MapEvent != null && nextLocatable1.MapEvent.IsSiegeAssault && nextLocatable1 == nextLocatable1.MapEvent.AttackerSide.LeaderParty.MobileParty)
            {
              float settlementAdvantage = Campaign.Current.Models.CombatSimulationModel.GetSettlementAdvantage(nextLocatable1.MapEvent.MapEventSettlement);
              if ((double) num5 * (double) MathF.Sqrt(settlementAdvantage) > (double) num6)
              {
                nextLocatable1 = MobileParty.FindNextLocatable(ref data1);
                continue;
              }
            }
            float avoidScore;
            float attackScore;
            this.CalculateInitiativeScoresForEnemy(nextLocatable1, out avoidScore, out attackScore, localAdvantage, aggressiveness);
            if (nextLocatable1.CurrentSettlement != null && nextLocatable1.MapEvent == null)
              attackScore = 0.0f;
            if ((double) avoidScore > 1.0)
            {
              List<(float, Vec2)> partiesAndTheirVecs = MobilePartyAi.DangerousPartiesAndTheirVecs;
              double num17 = (double) avoidScore;
              vec2_1 = v1 - this._mobileParty.Position2D;
              Vec2 vec2_2 = vec2_1.Normalized();
              (float, Vec2) valueTuple = ((float) num17, vec2_2);
              partiesAndTheirVecs.Add(valueTuple);
            }
            if (mobileParty == null)
            {
              if ((double) avoidScore > (double) bestInitiativeBehaviorScore || (double) avoidScore * 0.75 > (double) bestInitiativeBehaviorScore && bestInitiativeBehavior == AiBehavior.EngageParty)
              {
                bestInitiativeBehavior = AiBehavior.FleeToPoint;
                bestInitiativeTargetParty = nextLocatable1;
                bestInitiativeBehaviorScore = avoidScore;
              }
              if ((double) attackScore > (double) bestInitiativeBehaviorScore && ((double) bestInitiativeBehaviorScore < (double) attackScore * 0.75 || bestInitiativeBehavior == AiBehavior.EngageParty))
              {
                bestInitiativeBehavior = AiBehavior.EngageParty;
                bestInitiativeTargetParty = nextLocatable1;
                bestInitiativeBehaviorScore = attackScore;
              }
            }
            else if ((double) this._mobileParty.Aggressiveness > 0.0099999997764825821)
            {
              bestInitiativeBehavior = AiBehavior.DefendSettlement;
              bestInitiativeTargetParty = mobileParty;
              bestInitiativeBehaviorScore = attackScore;
            }
            nextLocatable1 = MobileParty.FindNextLocatable(ref data1);
          }
        }
      }
      if (bestInitiativeBehavior != AiBehavior.FleeToPoint && bestInitiativeBehavior != AiBehavior.FleeToGate)
        return;
      float num18 = 0.0f;
      for (int index1 = 0; index1 < 8; ++index1)
      {
        Vec2 v = new Vec2(MathF.Sin((float) ((double) index1 / 8.0 * 3.1415927410125732 * 2.0)), MathF.Cos((float) ((double) index1 / 8.0 * 3.1415927410125732 * 2.0)));
        float num19 = 0.0f;
        for (int index2 = 0; index2 < MobilePartyAi.DangerousPartiesAndTheirVecs.Count; ++index2)
        {
          float num20 = MobilePartyAi.DangerousPartiesAndTheirVecs[index2].Item2.DistanceSquared(v);
          if ((double) num20 > 1.0)
            num20 = (float) (1.0 + ((double) num20 - 1.0) * 0.5);
          num19 += num20 * MobilePartyAi.DangerousPartiesAndTheirVecs[index2].Item1;
        }
        if ((double) num19 > (double) num18)
        {
          averageEnemyVec = -v;
          num18 = num19;
        }
      }
    }

    private void SetAiBehavior(
      AiBehavior newAiBehavior,
      PartyBase targetPartyFigure,
      Vec2 bestTargetPoint)
    {
      IMapEntity mapEntity = targetPartyFigure != null ? (targetPartyFigure.IsSettlement ? (IMapEntity) targetPartyFigure.Settlement : (IMapEntity) targetPartyFigure.MobileParty) : (IMapEntity) null;
      this.SetShortTermBehavior(newAiBehavior, mapEntity);
      this.BehaviorTarget = bestTargetPoint;
      this.UpdateBehavior();
    }

    internal void SetShortTermBehavior(AiBehavior newBehavior, IMapEntity mapEntity)
    {
      AiBehavior shortTermBehavior = this._mobileParty.ShortTermBehavior;
      if (shortTermBehavior != newBehavior)
      {
        if (this.IsFleeBehavior(shortTermBehavior) && !this.IsFleeBehavior(newBehavior))
          this._numberOfRecentFleeingFromAParty = 0;
        this._mobileParty.ShortTermBehavior = newBehavior;
      }
      this.AiBehaviorMapEntity = mapEntity;
    }

    private void UpdateBehavior()
    {
      if (this._mobileParty.ShortTermBehavior == AiBehavior.GoToPoint || this._mobileParty.ShortTermBehavior == AiBehavior.FleeToPoint || this._mobileParty.ShortTermBehavior == AiBehavior.FleeToGate || this._mobileParty.ShortTermBehavior == AiBehavior.FleeToParty)
        this.SetNavigationModePoint(this._mobileParty.AiBehaviorTarget);
      else if ((this._mobileParty.ShortTermBehavior == AiBehavior.GoToSettlement || this._mobileParty.ShortTermBehavior == AiBehavior.RaidSettlement || this._mobileParty.ShortTermBehavior == AiBehavior.AssaultSettlement || this._mobileParty.ShortTermBehavior == AiBehavior.BesiegeSettlement) && this.AiBehaviorPartyBase != null && this.AiBehaviorPartyBase.IsValid)
      {
        this.SetNavigationModePoint(this.AiBehaviorPartyBase.Settlement.GatePosition);
      }
      else
      {
        switch (this._mobileParty.ShortTermBehavior)
        {
          case AiBehavior.Hold:
            this.SetNavigationModeHold();
            break;
          case AiBehavior.EngageParty:
            this.SetNavigationModeParty(this.AiBehaviorPartyBase.MobileParty);
            break;
          case AiBehavior.FleeToPoint:
            break;
          case AiBehavior.FleeToGate:
            break;
          case AiBehavior.FleeToParty:
            break;
          case AiBehavior.EscortParty:
            this.SetNavigationModeEscort(this.AiBehaviorPartyBase.MobileParty);
            break;
          case AiBehavior.DefendSettlement:
            break;
          default:
            Debug.FailedAssert("false", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Party\\MobilePartyAi.cs", nameof (UpdateBehavior), 1387);
            break;
        }
      }
    }

    public void RecalculateShortTermAi()
    {
      if (this._mobileParty.DefaultBehavior == AiBehavior.RaidSettlement)
        this.SetShortTermBehavior(AiBehavior.RaidSettlement, (IMapEntity) this._mobileParty.TargetSettlement);
      else if (this._mobileParty.DefaultBehavior == AiBehavior.BesiegeSettlement)
        this.SetShortTermBehavior(AiBehavior.BesiegeSettlement, (IMapEntity) this._mobileParty.TargetSettlement);
      else if (this._mobileParty.DefaultBehavior == AiBehavior.GoToSettlement)
        this.SetShortTermBehavior(AiBehavior.GoToSettlement, (IMapEntity) this._mobileParty.TargetSettlement);
      else if (this._mobileParty.DefaultBehavior == AiBehavior.EngageParty)
        this.SetShortTermBehavior(AiBehavior.EngageParty, (IMapEntity) this._mobileParty.TargetParty);
      else if (this._mobileParty.DefaultBehavior == AiBehavior.DefendSettlement)
        this.SetShortTermBehavior(AiBehavior.GoToPoint, (IMapEntity) this._mobileParty.TargetSettlement);
      else if (this._mobileParty.DefaultBehavior == AiBehavior.EscortParty)
      {
        this.SetShortTermBehavior(AiBehavior.EscortParty, (IMapEntity) this._mobileParty.TargetParty);
      }
      else
      {
        if (this.DefaultBehavior != AiBehavior.None)
          return;
        this._mobileParty.ShortTermBehavior = AiBehavior.None;
      }
    }

    private MobileParty GetNearbyPartyToFlee(MobileParty partyToFleeFrom, Vec2 fleeDirection)
    {
      (MobileParty, float) valueTuple = ((MobileParty) null, 0.0f);
      LocatableSearchData<MobileParty> data = MobileParty.StartFindingLocatablesAroundPosition(this._mobileParty.Position2D, 10f);
      MobileParty nextLocatable = MobileParty.FindNextLocatable(ref data);
      while (nextLocatable != null)
      {
        if (!nextLocatable.IsMilitia && !nextLocatable.IsGarrison && !nextLocatable.IsCaravan && nextLocatable != this._mobileParty && (nextLocatable.MapFaction == this._mobileParty.MapFaction || nextLocatable.IsBandit && this._mobileParty.IsBandit))
        {
          if (nextLocatable.AttachedTo != null || nextLocatable.CurrentSettlement != null || nextLocatable.MapEvent != null)
          {
            nextLocatable = MobileParty.FindNextLocatable(ref data);
            continue;
          }
          float num1 = nextLocatable.Army == null || !nextLocatable.Army.DoesLeaderPartyAndAttachedPartiesContain(this._mobileParty) ? nextLocatable.Party.TotalStrength : nextLocatable.Army.TotalStrength;
          if ((double) num1 > (double) this._mobileParty.Party.TotalStrength && (this._mobileParty.IsBandit || (double) num1 + (double) this._mobileParty.Party.TotalStrength > (double) partyToFleeFrom.Party.TotalStrength * 0.5))
          {
            Vec2 vec2 = nextLocatable.Position2D - this._mobileParty.Position2D;
            float length1 = vec2.Length;
            if ((double) length1 < 1.0 && (double) nextLocatable._lastCalculatedSpeed < (double) this._mobileParty._lastCalculatedSpeed)
            {
              nextLocatable = MobileParty.FindNextLocatable(ref data);
              continue;
            }
            float length2 = (partyToFleeFrom.Position2D - nextLocatable.Position2D).Length;
            double num2 = (double) vec2.Normalize();
            if ((double) vec2.DistanceSquared(fleeDirection) < 0.30000001192092896 + 0.10000000149011612 * (10.0 - (double) Math.Min(10f, length1)) && (double) length1 < (double) length2 * 0.86000001430511475)
            {
              float num3 = (float) ((double) length1 * 0.6600000262260437 + (double) num1 * 0.34000000357627869);
              if ((double) valueTuple.Item2 < (double) num3)
              {
                valueTuple.Item1 = nextLocatable;
                valueTuple.Item2 = num3;
              }
            }
          }
        }
        nextLocatable = MobileParty.FindNextLocatable(ref data);
      }
      return valueTuple.Item1;
    }

    private (AiBehavior, Settlement) GetBehaviorForNearbySettlementToFlee(
      Vec2 partyToFleeFromPosition,
      Vec2 fleeDirection)
    {
      LocatableSearchData<Settlement> data = Campaign.Current.SettlementLocator.StartFindingLocatablesAroundPosition(this._mobileParty.Position2D, 20f);
      for (Settlement nextLocatable = Campaign.Current.SettlementLocator.FindNextLocatable(ref data); nextLocatable != null; nextLocatable = Campaign.Current.SettlementLocator.FindNextLocatable(ref data))
      {
        if (nextLocatable.IsFortification && nextLocatable.MapFaction == this._mobileParty.MapFaction && !nextLocatable.IsUnderSiege)
        {
          Vec2 vec2 = nextLocatable.GatePosition - this._mobileParty.Position2D;
          float length1 = vec2.Length;
          float length2 = (partyToFleeFromPosition - nextLocatable.GatePosition).Length;
          if ((double) length1 < (double) length2 * 0.86000001430511475)
          {
            if ((double) length1 > 1.0)
              return (AiBehavior.FleeToGate, nextLocatable);
            this.DisableForHours(3);
            return (AiBehavior.GoToSettlement, nextLocatable);
          }
          double num = (double) vec2.Normalize();
          if ((double) vec2.DistanceSquared(fleeDirection) < 0.30000001192092896 + 0.10000000149011612 * (10.0 - (double) MathF.Min(10f, length1)))
            return (double) length1 <= 1.0 ? (AiBehavior.GoToSettlement, nextLocatable) : (AiBehavior.FleeToGate, nextLocatable);
        }
      }
      return (AiBehavior.None, (Settlement) null);
    }

    private float GetMaxPatrolRadiusForSettlement()
    {
      if (this._mobileParty.TargetSettlement != null)
      {
        if (this._mobileParty.TargetSettlement.IsHideout)
          return 25f;
        if (this._mobileParty.TargetSettlement.IsFortification)
          return 30f;
        if (this._mobileParty.TargetSettlement.IsVillage)
          return 15f;
      }
      return 0.0f;
    }

    private float CalculateStanceScore(MobileParty otherParty)
    {
      if (FactionManager.IsAtWarAgainstFaction(this._mobileParty.MapFaction, otherParty.MapFaction))
        return 1f;
      return FactionManager.IsAlliedWithFaction(this._mobileParty.MapFaction, otherParty.MapFaction) ? -1f : 0.0f;
    }

    private void CalculateInitiativeScoresForEnemy(
      MobileParty enemyParty,
      out float avoidScore,
      out float attackScore,
      float localAdvantage,
      float maxAggressiveness)
    {
      float num1 = 1f;
      if (enemyParty.IsCaravan)
        num1 = this._mobileParty.IsBandit ? 2f : (this._mobileParty.Army == null ? 1.5f : 1f);
      else if (enemyParty.IsBandit || (double) enemyParty.Aggressiveness < 0.10000000149011612)
        num1 = 0.7f;
      else if ((this._mobileParty.DefaultBehavior == AiBehavior.GoAroundParty || this._mobileParty.ShortTermBehavior == AiBehavior.GoAroundParty) && enemyParty != this._mobileParty.TargetParty)
        num1 = 0.7f;
      int num2 = 0;
      for (int index = 0; index < this._lastTargetedParties.Count; ++index)
      {
        if (enemyParty == this._lastTargetedParties[index])
          ++num2;
      }
      if (num2 > 0)
        num1 *= (float) (3.0 / ((double) num2 + 3.0));
      if (enemyParty.MapEvent == null && (double) this._mobileParty._lastCalculatedSpeed < (double) enemyParty.Speed * 1.1000000238418579 && (this._mobileParty.DefaultBehavior != AiBehavior.GoAroundParty || this._mobileParty.TargetParty != enemyParty) && (this._mobileParty.DefaultBehavior != AiBehavior.DefendSettlement || enemyParty != this._mobileParty.TargetSettlement.LastAttackerParty))
      {
        float b = MathF.Max(0.5f, (float) (((double) this._mobileParty.Speed + 0.10000000149011612) / ((double) enemyParty.Speed + 0.10000000149011612))) / 1.1f;
        num1 *= MathF.Max(0.8f, b) * MathF.Max(0.8f, b);
      }
      float num3 = this._mobileParty.IsCaravan || this._mobileParty.IsVillager ? 0.9f : (enemyParty.IsGarrison || enemyParty.IsMilitia || enemyParty.CurrentSettlement != null ? 0.4f : 0.7f);
      float num4 = 4.8f * num1;
      float num5 = 4.8f * num3;
      float num6 = (float) ((double) num4 * ((1.0 + (this._mobileParty.Army == null || this._mobileParty.Army.LeaderParty == null || enemyParty.BesiegedSettlement != this._mobileParty.Army.LeaderParty.TargetSettlement && (this._mobileParty.Army.LeaderParty.TargetSettlement == null || enemyParty != this._mobileParty.Army.LeaderParty.TargetSettlement.LastAttackerParty) ? (double) this.AttackInitiative : 1.0)) / 2.0) * (enemyParty.Army != null ? (double) MathF.Pow((float) enemyParty.Army.Parties.Count, 0.33f) : 1.0));
      float num7 = num5 * (float) ((1.0 + (double) this.AvoidInitiative) / 2.0);
      int num8 = enemyParty.MapEvent != null ? 1 : (enemyParty.BesiegedSettlement != null ? 1 : 0);
      if (num8 != 0 || this._mobileParty.DefaultBehavior == AiBehavior.EngageParty && this._mobileParty.TargetParty == enemyParty || this._mobileParty.DefaultBehavior == AiBehavior.GoAroundParty && this._mobileParty.TargetParty == enemyParty)
      {
        num7 = 2.88f;
        num6 = 7.20000029f;
      }
      Vec2 otherPartyDif = (enemyParty.BesiegedSettlement != null ? enemyParty.VisualPosition2DWithoutError : enemyParty.Position2D) - this._mobileParty.Position2D;
      float length = otherPartyDif.Length;
      float num9 = num6 / (length + 1E-05f);
      float num10 = num7 / (length + 1E-05f);
      float num11 = MBMath.ClampFloat(num8 == 0 ? num9 * num9 * num9 : 1f, 0.05f, 1f);
      float num12 = MBMath.ClampFloat(num10 * num10 * num10, 0.05f, 1f);
      float num13 = 1f;
      if (enemyParty.IsMoving && enemyParty.SiegeEvent == null && enemyParty.MapEvent == null && (this._mobileParty.DefaultBehavior != AiBehavior.GoAroundParty || this._mobileParty.TargetParty != enemyParty))
        num13 = this.CalculateInitiativeSpeedScore(enemyParty, otherPartyDif);
      float num14 = MBMath.ClampFloat((float) (0.5 * (1.0 + (double) localAdvantage)), 0.05f, 2f);
      float num15 = MBMath.ClampFloat((double) localAdvantage < 1.0 ? MBMath.ClampFloat(1f / localAdvantage, 0.05f, 2f) : 0.0f, 0.05f, 2f);
      float stanceScore = this.CalculateStanceScore(enemyParty);
      float num16 = !enemyParty.IsLordParty || enemyParty.LeaderHero == null || !enemyParty.LeaderHero.IsLord ? this.AttackInitiative : 1f;
      if ((double) this._mobileParty.Aggressiveness < 0.01)
        maxAggressiveness = this._mobileParty.Aggressiveness;
      float num17 = enemyParty.MapEvent == null || (double) maxAggressiveness <= 0.10000000149011612 ? maxAggressiveness : MathF.Max((float) (1.0 + (enemyParty.MapEvent.IsSallyOut ? 0.30000001192092896 : 0.0)), maxAggressiveness);
      float num18 = this._mobileParty.DefaultBehavior != AiBehavior.DefendSettlement || (enemyParty.BesiegedSettlement == null || this.AiBehaviorPartyBase != enemyParty.BesiegedSettlement.Party) && (enemyParty.MapEvent == null || enemyParty.MapEvent.MapEventSettlement == null || this.AiBehaviorPartyBase != enemyParty.MapEvent.MapEventSettlement.Party) ? 1f : 1.1f;
      float num19 = 1f;
      if (this.IsFleeBehavior(enemyParty.ShortTermBehavior) && enemyParty.ShortTermTargetParty == this._mobileParty)
        num19 = this.CalculateContinueChasingScore(enemyParty);
      attackScore = this.CanAttack(enemyParty) ? 1.06f * num18 * num11 * num14 * stanceScore * num13 * num17 * num19 * num16 : 0.0f;
      float num20 = !enemyParty.IsLordParty || enemyParty.LeaderHero == null || !enemyParty.LeaderHero.IsLord ? this.AvoidInitiative : 1f;
      if ((double) attackScore < 1.0)
      {
        if (enemyParty.IsGarrison && this._numberOfRecentFleeingFromAParty > 0)
        {
          avoidScore = 0.0f;
          attackScore = 0.0f;
          if (enemyParty != this._mobileParty.ShortTermTargetParty)
            return;
          this.RecalculateShortTermAi();
        }
        else
          avoidScore = this.CanAvoid(enemyParty) ? (float) (0.943396270275116 * (double) num20 * (double) num12 * ((double) stanceScore > 0.0099999997764825821 ? 1.0 : 0.0)) * num15 : 0.0f;
      }
      else
        avoidScore = 0.0f;
    }

    private float CalculateInitiativeSpeedScore(MobileParty enemyParty, Vec2 otherPartyDif)
    {
      float num1 = 1f;
      float length = otherPartyDif.Length;
      float num2 = (float) (((double) this._mobileParty.Speed + 0.10000000149011612) / ((double) enemyParty.Speed + 0.10000000149011612));
      float num3 = enemyParty.IsLordParty ? 4.5f : 3f;
      float num4;
      if ((double) num2 < 1.1000000238418579 && (double) length < (double) num3 && (double) length > 0.5)
      {
        float f = enemyParty.Bearing.DotProduct(otherPartyDif);
        float num5 = 2f;
        float num6 = num5 * 0.5f;
        if ((double) f > (double) num5)
          num1 = 0.0f;
        else if ((double) f > (double) num5 * 0.5)
          num1 = (float) (1.0 - ((double) f - (double) num6) / ((double) num5 - (double) num6));
        else if ((double) f < 0.0)
          num1 = (float) (1.0 + (1.0 + (1.1000000238418579 / (double) num2 - 1.0) * (double) MathF.Min(1f, MathF.Abs(f) / 3f) - 1.0) * (1.0 - (double) MathF.Max(0.0f, length - num3 * 0.5f) / (double) num3 * 0.5 * 0.67000001668930054));
        num4 = MathF.Pow(num2 * 1.5f * MathF.Pow(num2 / 1.1f, 1f - MathF.Max(0.8f, 0.5f * num1)), MathF.Min(2.5f, length - 1f));
      }
      else
        num4 = 1f;
      return MBMath.ClampFloat(num4, 0.0001f, 1f);
    }

    private float CalculateContinueChasingScore(MobileParty enemyParty)
    {
      float num1 = this._mobileParty.Army == null || this._mobileParty.Army.LeaderParty != this._mobileParty ? this._mobileParty.Party.TotalStrength : this._mobileParty.Army.TotalStrength;
      float num2 = (float) ((enemyParty.Army == null || enemyParty.Army.LeaderParty != this._mobileParty ? (double) enemyParty.Party.TotalStrength : (double) enemyParty.Army.TotalStrength) / ((double) num1 + 0.0099999997764825821));
      float num3 = (float) (1.0 + 0.0099999997764825821 * (double) enemyParty.Ai._numberOfRecentFleeingFromAParty);
      float num4 = Math.Min(1f, (this._mobileParty.Position2D - enemyParty.Position2D).Length / 3f);
      Settlement toSettlement = !this._mobileParty.IsBandit ? (!this._mobileParty.IsLordParty || this._mobileParty.LeaderHero == null || !this._mobileParty.LeaderHero.IsMinorFactionHero ? SettlementHelper.FindNearestFortification((Func<Settlement, bool>) (x => x.MapFaction == this._mobileParty.MapFaction)) : this._mobileParty.MapFaction.FactionMidSettlement) : this._mobileParty.BanditPartyComponent.Hideout?.Settlement;
      float num5 = Campaign.AverageDistanceBetweenTwoFortifications * 3f;
      if (toSettlement != null)
        num5 = Campaign.Current.Models.MapDistanceModel.GetDistance(this._mobileParty, toSettlement);
      float num6 = num5 / (Campaign.AverageDistanceBetweenTwoFortifications * 3f);
      float num7 = MBMath.Map(1f + (float) Math.Pow((double) enemyParty.Speed / ((double) this._mobileParty.Speed - 0.25), 3.0), 0.0f, 5.2f, 0.0f, 2f);
      float num8 = 60000f;
      float num9 = 10000f;
      double num10 = (enemyParty.LeaderHero != null ? (double) (enemyParty.PartyTradeGold + enemyParty.LeaderHero.Gold) : (double) enemyParty.PartyTradeGold) / (enemyParty.IsCaravan ? (double) num9 : (double) num8);
      float num11 = enemyParty.LeaderHero != null ? (enemyParty.LeaderHero.IsKingdomLeader || enemyParty.LeaderHero.IsClanLeader ? 1.5f : 1f) : 0.75f;
      float num12 = num2 * num6 * num7 * num3 * num4;
      double num13 = (double) num11;
      return MBMath.ClampFloat((float) (num10 * num13 / ((double) num12 + 1.0 / 1000.0)), 0.005f, 3f);
    }

    private bool GetAccessibleTargetPointInDirection(
      out Vec2 targetPoint,
      Vec2 direction,
      float distance,
      Vec2 alternativePosition,
      int neededTriesForAlternative,
      float rotationChangeLimitAddition = 0.1f)
    {
      targetPoint = this._mobileParty.Position2D;
      float num1 = 2f * rotationChangeLimitAddition;
      float num2 = 1f;
      bool pointInDirection = false;
      int num3 = 0;
      while (!pointInDirection)
      {
        Vec2 vec2 = direction;
        float randomFloat = MBRandom.RandomFloat;
        vec2.RotateCCW((randomFloat - 0.5f) * num1);
        targetPoint = this._mobileParty.Position2D + vec2 * distance * num2;
        ++num3;
        num1 += rotationChangeLimitAddition;
        num2 *= 0.97f;
        PathFaceRecord faceIndex = Campaign.Current.MapSceneWrapper.GetFaceIndex(targetPoint);
        if (faceIndex.IsValid() && Campaign.Current.MapSceneWrapper.AreFacesOnSameIsland(faceIndex, this._mobileParty.CurrentNavigationFace, false) && ((double) targetPoint.x > (double) Campaign.Current.MinSettlementX - 50.0 || (double) targetPoint.x > (double) this._mobileParty.Position2D.x) && ((double) targetPoint.y > (double) Campaign.Current.MinSettlementY - 50.0 || (double) targetPoint.y > (double) this._mobileParty.Position2D.y) && ((double) targetPoint.x < (double) Campaign.Current.MaxSettlementX + 50.0 || (double) targetPoint.x < (double) this._mobileParty.Position2D.x) && ((double) targetPoint.y < (double) Campaign.Current.MaxSettlementY + 50.0 || (double) targetPoint.y < (double) this._mobileParty.Position2D.y))
          pointInDirection = num3 >= neededTriesForAlternative || MobilePartyAi.CheckIfThereIsAnyHugeObstacleBetweenPartyAndTarget(this._mobileParty, targetPoint);
        if (num3 >= neededTriesForAlternative)
        {
          pointInDirection = true;
          targetPoint = alternativePosition;
        }
      }
      return pointInDirection;
    }

    private bool CanAvoid(MobileParty targetParty)
    {
      return (double) targetParty.Aggressiveness > 0.0099999997764825821 && targetParty.Party.IsMobile || targetParty.IsGarrison;
    }

    private bool CanAttack(MobileParty targetParty)
    {
      return ((targetParty != MobileParty.MainParty || !Game.Current.CheatMode ? 1 : (CampaignCheats.MainPartyIsAttackable ? 1 : 0)) & (targetParty != MobileParty.MainParty ? (true ? 1 : 0) : (this.DoNotAttackMainPartyUntil.IsPast ? 1 : 0))) != 0;
    }

    private bool IsEnemy(PartyBase party)
    {
      return FactionManager.IsAtWarAgainstFaction(party.MapFaction, this._mobileParty.MapFaction);
    }

    private bool IsFleeBehavior(AiBehavior aiBehavior)
    {
      return aiBehavior == AiBehavior.FleeToPoint || aiBehavior == AiBehavior.FleeToGate || aiBehavior == AiBehavior.FleeToParty;
    }

    public bool IsFleeing()
    {
      return this.IsFleeBehavior(this._mobileParty.ShortTermBehavior) || this.IsFleeBehavior(this._mobileParty.DefaultBehavior);
    }

    internal void CacheTargetPartyVariablesAtFrameStart(
      ref MobileParty.CachedPartyVariables variables)
    {
      if (this.MoveTargetParty == null)
        return;
      variables.TargetPartyPositionAtFrameStart = this.MoveTargetParty.Position2D;
      variables.TargetPartyCurrentNavigationFaceAtFrameStart = this.MoveTargetParty.CurrentNavigationFace;
    }

    private bool ComputePath(Vec2 newTargetPosition)
    {
      bool path = false;
      if (this._mobileParty.CurrentNavigationFace.IsValid())
      {
        this._targetAiFaceIndex = Campaign.Current.MapSceneWrapper.GetFaceIndex(newTargetPosition);
        if (this._targetAiFaceIndex.IsValid())
          path = Campaign.Current.MapSceneWrapper.GetPathBetweenAIFaces(this._mobileParty.CurrentNavigationFace, this._targetAiFaceIndex, this._mobileParty.Position2D, newTargetPosition, 0.1f, this.Path);
        else
          Debug.FailedAssert("Path finding target is not valid", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Party\\MobilePartyAi.cs", nameof (ComputePath), 2016);
      }
      this.PathBegin = 0;
      if (!path)
        this._aiPathMode = false;
      return path;
    }

    private void DoAIMove(ref MobileParty.CachedPartyVariables variables)
    {
      Vec2 finalTargetPosition;
      PathFaceRecord finalTargetNavigationFace;
      bool forceNoPathMode;
      this.GetTargetPositionAndFace(ref variables, out finalTargetPosition, out finalTargetNavigationFace, out forceNoPathMode);
      if (this._aiPathMode)
      {
        float num = (double) this._aiPathLastPosition.DistanceSquared(this._mobileParty.Position2D) > 108.0 ? 3f : this._aiPathLastPosition.DistanceSquared(this._mobileParty.Position2D) / 36f;
        if (forceNoPathMode || finalTargetNavigationFace.FaceIndex != this._aiPathLastFace.FaceIndex || (double) this._aiPathLastPosition.DistanceSquared(finalTargetPosition) > (double) num)
        {
          this._aiPathMode = false;
          this._aiPathLastFace = PathFaceRecord.NullFaceRecord;
        }
      }
      if (!this._aiPathMode && !forceNoPathMode && !this._aiPathNotFound)
      {
        if ((finalTargetNavigationFace.FaceIndex != this._aiPathLastFace.FaceIndex || this._aiPathNeeded) && finalTargetNavigationFace.IsValid())
        {
          if (this._mobileParty.CurrentNavigationFace.FaceIndex != finalTargetNavigationFace.FaceIndex || this._aiPathNeeded)
          {
            this._aiPathNotFound = !this.ComputePath(finalTargetPosition);
            this._aiPathNeeded = false;
            if (!this._aiPathNotFound)
            {
              this._aiPathLastFace = finalTargetNavigationFace;
              this._aiPathLastPosition = finalTargetPosition;
              this._aiPathMode = true;
            }
          }
          else
            this._aiPathMode = false;
        }
        else if (finalTargetNavigationFace.FaceIndex == this._aiPathLastFace.FaceIndex && this._mobileParty.CurrentNavigationFace.FaceIndex != finalTargetNavigationFace.FaceIndex)
          this._aiPathMode = true;
      }
      if (this._aiPathMode)
        return;
      this.NextTargetPosition = finalTargetPosition;
    }

    internal void DoAiPathMode(ref MobileParty.CachedPartyVariables variables)
    {
      if (variables.IsAttachedArmyMember)
      {
        this._aiPathMode = false;
      }
      else
      {
        this.DoAIMove(ref variables);
        if (!this._aiPathMode)
          return;
        bool flag;
        do
        {
          flag = false;
          this.NextTargetPosition = this.Path[this.PathBegin];
          float lengthSquared = (this.NextTargetPosition - variables.CurrentPosition).LengthSquared;
          if ((double) lengthSquared < (double) variables.NextMoveDistance * (double) variables.NextMoveDistance)
          {
            flag = true;
            variables.NextMoveDistance -= MathF.Sqrt(lengthSquared);
            variables.LastCurrentPosition = variables.CurrentPosition;
            variables.CurrentPosition = this.NextTargetPosition;
            ++this.PathBegin;
          }
        }
        while (flag && this.PathBegin < this.Path.Size);
        if (this.PathBegin < this.Path.Size)
          return;
        this._aiPathMode = false;
        this._aiPathNeeded = false;
        if (this.Path.Size <= 0)
          return;
        variables.CurrentPosition = variables.LastCurrentPosition;
        this.NextTargetPosition = this.Path[this.Path.Size - 1];
      }
    }

    public void ResetAiBehaviorObject() => this.AiBehaviorPartyBase = (PartyBase) null;

    private void UpdatePathModeWithPosition(Vec2 newTargetPosition)
    {
      this._moveTargetPoint = newTargetPosition;
      this._moveTargetAiFaceIndex = Campaign.Current.MapSceneWrapper.GetFaceIndex(newTargetPosition);
    }

    internal void GetTargetPositionAndFace(
      ref MobileParty.CachedPartyVariables variables,
      out Vec2 finalTargetPosition,
      out PathFaceRecord finalTargetNavigationFace,
      out bool forceNoPathMode)
    {
      finalTargetPosition = this._mobileParty.Position2D;
      finalTargetNavigationFace = this._mobileParty.CurrentNavigationFace;
      forceNoPathMode = false;
      if (this.PartyMoveMode == MoveModeType.Point)
      {
        finalTargetPosition = this._moveTargetPoint;
        finalTargetNavigationFace = this._moveTargetAiFaceIndex;
        forceNoPathMode = this.ForceAiNoPathMode;
      }
      else if (this.PartyMoveMode == MoveModeType.Party)
      {
        if (!this.MoveTargetParty.Party.IsValid)
          return;
        if (!this.MoveTargetParty.IsMoving)
        {
          finalTargetPosition = variables.TargetPartyPositionAtFrameStart;
          finalTargetNavigationFace = variables.TargetPartyCurrentNavigationFaceAtFrameStart;
        }
        else
        {
          Vec2 positionAtFrameStart = variables.TargetPartyPositionAtFrameStart;
          if (PartyBase.IsPositionOkForTraveling(positionAtFrameStart))
          {
            finalTargetPosition = positionAtFrameStart;
            finalTargetNavigationFace = Campaign.Current.MapSceneWrapper.GetFaceIndex(positionAtFrameStart);
          }
          else
          {
            finalTargetPosition = variables.TargetPartyPositionAtFrameStart;
            finalTargetNavigationFace = variables.TargetPartyCurrentNavigationFaceAtFrameStart;
          }
        }
      }
      else
      {
        if (this.PartyMoveMode != MoveModeType.Escort)
          return;
        if (this.MoveTargetParty != null && this.MoveTargetParty.Party.IsValid && this.MoveTargetParty.CurrentSettlement == null && this._mobileParty.CurrentSettlement == null)
        {
          if ((double) variables.TargetPartyPositionAtFrameStart.DistanceSquared(this._mobileParty.Position2D) > 25.0)
          {
            finalTargetPosition = variables.TargetPartyPositionAtFrameStart;
            finalTargetNavigationFace = variables.TargetPartyCurrentNavigationFaceAtFrameStart;
          }
          else
          {
            float num = this._mobileParty.Army != null ? 0.0f : (this.MoveTargetParty.DefaultBehavior != AiBehavior.DefendSettlement && this.MoveTargetParty.DefaultBehavior != AiBehavior.BesiegeSettlement && this.MoveTargetParty.DefaultBehavior != AiBehavior.RaidSettlement || (double) this._mobileParty.Party.MobileParty.Position2D.DistanceSquared(this.MoveTargetParty.AiBehaviorTarget) >= 100.0 ? 2.4f : 1.2f);
            while (true)
            {
              do
              {
                finalTargetPosition = variables.TargetPartyPositionAtFrameStart + num * this._formationPosition;
                PathFaceRecord faceIndex = Campaign.Current.MapSceneWrapper.GetFaceIndex(this._mobileParty.Position2D);
                finalTargetNavigationFace = Campaign.Current.MapSceneWrapper.GetFaceIndex(finalTargetPosition);
                PathFaceRecord faceAtFrameStart = variables.TargetPartyCurrentNavigationFaceAtFrameStart;
                Vec2.StackArray6Vec2 stackArray6Vec2_1 = new Vec2.StackArray6Vec2();
                PathFaceRecord.StackArray6PathFaceRecord array6PathFaceRecord1 = new PathFaceRecord.StackArray6PathFaceRecord();
                for (int index = 0; index < 6; ++index)
                {
                  stackArray6Vec2_1[index] = new Vec2((float) (((double) finalTargetPosition.x * (double) index + (double) this._mobileParty.Position2D.x * (double) (6 - index)) / 6.0), (float) (((double) finalTargetPosition.y * (double) index + (double) this._mobileParty.Position2D.y * (double) (6 - index)) / 6.0));
                  array6PathFaceRecord1[index] = Campaign.Current.MapSceneWrapper.GetFaceIndex(stackArray6Vec2_1[index]);
                }
                bool flag1 = Campaign.Current.MapSceneWrapper.AreFacesOnSameIsland(faceIndex, finalTargetNavigationFace, false);
                for (int index = 0; index < 6 & flag1; ++index)
                {
                  if (faceIndex.FaceIndex != array6PathFaceRecord1[index].FaceIndex && !Campaign.Current.MapSceneWrapper.AreFacesOnSameIsland(faceIndex, array6PathFaceRecord1[index], false))
                    flag1 = false;
                }
                if (flag1)
                {
                  Vec2.StackArray6Vec2 stackArray6Vec2_2 = new Vec2.StackArray6Vec2();
                  PathFaceRecord.StackArray6PathFaceRecord array6PathFaceRecord2 = new PathFaceRecord.StackArray6PathFaceRecord();
                  for (int index = 0; index < 6; ++index)
                  {
                    stackArray6Vec2_2[index] = new Vec2((float) (((double) finalTargetPosition.x * (double) index + (double) variables.TargetPartyPositionAtFrameStart.x * (double) (6 - index)) / 6.0), (float) (((double) finalTargetPosition.y * (double) index + (double) variables.TargetPartyPositionAtFrameStart.y * (double) (6 - index)) / 6.0));
                    array6PathFaceRecord2[index] = Campaign.Current.MapSceneWrapper.GetFaceIndex(stackArray6Vec2_2[index]);
                  }
                  bool flag2 = Campaign.Current.MapSceneWrapper.AreFacesOnSameIsland(finalTargetNavigationFace, faceAtFrameStart, false);
                  for (int index = 0; index < 6 & flag2; ++index)
                  {
                    if (variables.TargetPartyCurrentNavigationFaceAtFrameStart.FaceIndex != array6PathFaceRecord2[index].FaceIndex && !Campaign.Current.MapSceneWrapper.AreFacesOnSameIsland(variables.TargetPartyCurrentNavigationFaceAtFrameStart, array6PathFaceRecord2[index], false))
                      flag2 = false;
                  }
                  if (flag2)
                    goto label_38;
                }
                num = num * 0.75f - 0.1f;
                if ((double) num < 0.10000000149011612)
                  goto label_39;
              }
              while ((double) num > 0.30000001192092896);
              num = 0.0f;
            }
label_38:
            return;
label_39:;
          }
        }
        else
          this.SetMoveModeHold();
      }
    }

    internal void SetNavigationModeHold()
    {
      this.PartyMoveMode = MoveModeType.Hold;
      this._aiPathMode = false;
      this._aiPathNeeded = false;
      this.NextTargetPosition = this._mobileParty.Position2D;
      this.MoveTargetParty = (MobileParty) null;
    }

    private void SetNavigationModePoint(Vec2 newTargetPosition)
    {
      this.PartyMoveMode = MoveModeType.Point;
      this.UpdatePathModeWithPosition(newTargetPosition);
      this._aiPathNotFound = false;
      this.MoveTargetParty = (MobileParty) null;
    }

    private void SetNavigationModeParty(MobileParty targetParty)
    {
      this.PartyMoveMode = MoveModeType.Party;
      this.MoveTargetParty = targetParty;
      this._aiPathNotFound = false;
    }

    private void SetNavigationModeEscort(MobileParty targetParty)
    {
      if (this.PartyMoveMode == MoveModeType.Escort && this.MoveTargetParty == targetParty)
        return;
      this.PartyMoveMode = MoveModeType.Escort;
      this.MoveTargetParty = targetParty;
      this._aiPathNotFound = false;
    }

    public void DisableForHours(int hours)
    {
      this._isDisabled = true;
      this._enableAgainAtHour = CampaignTime.Now + CampaignTime.Hours((float) hours);
    }

    public void DisableAi()
    {
      this._isDisabled = true;
      this._enableAgainAtHour = CampaignTime.Never;
    }

    public void EnableAi()
    {
      this._isDisabled = false;
      this._enableAgainAtHour = CampaignTime.Now;
    }

    public bool EnableAgainAtHourIsPast() => this._enableAgainAtHour.IsPast;

    public void SetDoNotAttackMainParty(int hours)
    {
      if ((double) this.DoNotAttackMainPartyUntil.RemainingHoursFromNow >= (double) hours)
        return;
      this.DoNotAttackMainPartyUntil = CampaignTime.HoursFromNow((float) hours);
    }

    public void SetAsMainParty() => this.SetInitiative(0.0f, 0.0f, 1E+08f);

    internal void ForceDefaultBehaviorUpdate() => this.DefaultBehaviorNeedsUpdate = true;

    public void SetInitiative(float attackInitiative, float avoidInitiative, float hoursUntilReset)
    {
      if (this._mobileParty == MobileParty.MainParty)
        return;
      this._attackInitiative = attackInitiative;
      this._avoidInitiative = avoidInitiative;
      this._initiativeRestoreTime = CampaignTime.HoursFromNow(hoursUntilReset);
    }

    public void SetDoNotMakeNewDecisions(bool doNotMakeNewDecisions)
    {
      this.DoNotMakeNewDecisions = doNotMakeNewDecisions;
    }

    internal void InitializeForOldSaves(
      float attackInitiative,
      float avoidInitiative,
      CampaignTime initiativeRestoreTime,
      int numberOfRecentFleeingFromAParty,
      AiBehavior aiBehavior,
      Vec2 oldAiBehaviorTarget,
      bool oldAiPathMode,
      bool oldAiPathNeeded,
      MoveModeType oldPartyMoveMode,
      MobileParty oldMoveTargetParty,
      Vec2 oldNextTargetPosition,
      Vec2 oldMoveTargetPoint,
      Vec2 oldAiPathLastPosition,
      Vec2 oldFormationPosition,
      IMapEntity oldAiBehaviorMapEntity,
      CampaignTime oldDoNotAttackMainPartyUntil)
    {
      this._attackInitiative = attackInitiative;
      this._avoidInitiative = avoidInitiative;
      this._initiativeRestoreTime = initiativeRestoreTime;
      this._numberOfRecentFleeingFromAParty = numberOfRecentFleeingFromAParty;
      this._defaultBehavior = aiBehavior;
      this.BehaviorTarget = oldAiBehaviorTarget;
      this._aiPathMode = oldAiPathMode;
      this._aiPathNeeded = oldAiPathNeeded;
      this.PartyMoveMode = oldPartyMoveMode;
      this.MoveTargetParty = oldMoveTargetParty;
      this.NextTargetPosition = oldNextTargetPosition;
      this._moveTargetPoint = oldMoveTargetPoint;
      this._aiPathLastPosition = oldAiPathLastPosition;
      this._formationPosition = oldFormationPosition;
      this.AiBehaviorMapEntity = oldAiBehaviorMapEntity;
      this.DoNotAttackMainPartyUntil = oldDoNotAttackMainPartyUntil;
    }

    internal void RecoverPositionsForNavMeshUpdate()
    {
      if (this._moveTargetPoint.IsNonZero() && !PartyBase.IsPositionOkForTraveling(this._moveTargetPoint))
      {
        Debug.Print("Target of " + this._mobileParty.StringId + " is not valid! (" + (object) this._mobileParty.Position2D.x + ", " + (object) this._mobileParty.Position2D.y + ") Party will be moved to a valid position.");
        Settlement targetSettlement = this._mobileParty.TargetSettlement;
        this._moveTargetPoint = targetSettlement != null ? targetSettlement.GatePosition : this._mobileParty.Position2D;
        this._mobileParty.TargetPosition = this._moveTargetPoint;
        this.NextTargetPosition = this._moveTargetPoint;
        this.BehaviorTarget = this._moveTargetPoint;
      }
      Vec2 vec2 = this._mobileParty.TargetPosition;
      if (vec2.IsNonZero() && !PartyBase.IsPositionOkForTraveling(this._mobileParty.TargetPosition))
        this._mobileParty.TargetPosition = Vec2.Zero;
      if (this.DefaultBehavior == AiBehavior.Hold)
        return;
      vec2 = this._mobileParty.TargetPosition;
      if (!vec2.IsNonZero() || PartyBase.IsPositionOkForTraveling(this._mobileParty.TargetPosition))
      {
        vec2 = this.NextTargetPosition;
        if ((!vec2.IsNonZero() || PartyBase.IsPositionOkForTraveling(this.NextTargetPosition)) && (!this.BehaviorTarget.IsNonZero() || PartyBase.IsPositionOkForTraveling(this.BehaviorTarget)))
          return;
      }
      this.ForceDefaultBehaviorUpdate();
      this.SetMoveModeHold();
      this.SetNavigationModeHold();
    }

    internal void ResetNumberOfRecentFleeing() => this._numberOfRecentFleeingFromAParty = 0;

    internal static bool CheckIfThereIsAnyHugeObstacleBetweenPartyAndTarget(
      MobileParty party,
      Vec2 newTargetPosition)
    {
      IMapScene mapSceneWrapper = Campaign.Current.MapSceneWrapper;
      Vec2 position2D = party.Position2D;
      Vec2 position1 = new Vec2((float) (((double) newTargetPosition.x + (double) position2D.x * 3.0) * 0.25), (float) (((double) newTargetPosition.y + (double) position2D.y * 3.0) * 0.25));
      PathFaceRecord faceIndex1 = mapSceneWrapper.GetFaceIndex(position1);
      Vec2 position2 = new Vec2((float) (((double) newTargetPosition.x + (double) position2D.x) * 0.5), (float) (((double) newTargetPosition.y + (double) position2D.y) * 0.5));
      PathFaceRecord faceIndex2 = mapSceneWrapper.GetFaceIndex(position2);
      Vec2 position3 = new Vec2((float) (((double) newTargetPosition.x * 3.0 + (double) position2D.x) * 0.25), (float) (((double) newTargetPosition.y * 3.0 + (double) position2D.y) * 0.25));
      PathFaceRecord faceIndex3 = mapSceneWrapper.GetFaceIndex(position3);
      return faceIndex1.IsValid() && mapSceneWrapper.AreFacesOnSameIsland(faceIndex1, party.CurrentNavigationFace, false) && faceIndex2.IsValid() && mapSceneWrapper.AreFacesOnSameIsland(faceIndex2, party.CurrentNavigationFace, false) && faceIndex3.IsValid() && mapSceneWrapper.AreFacesOnSameIsland(faceIndex3, party.CurrentNavigationFace, false);
    }
  }
}
